// -*- coding: utf-8 -*-
/****************************************************************************
 * Elisa 1.0                                                                *
 *--------------------------------------------------------------------------*
 * Author: Laurent Granvilliers, Vincent Sorin                              *
 * Copyright (c) 2004 Laboratoire d'Informatique de Nantes Atlantique       *
 *--------------------------------------------------------------------------*
 * elisa is distributed WITHOUT ANY WARRANTY. Read the associated           *
 * COPYRIGHT file for more details.                                         *
 ****************************************************************************/

/**
 * @file elisa_interval_traits.h
 * @brief Trait for interval libraries
 */


#ifndef _ELISA_INTERVAL_TRAITS_H
#define _ELISA_INTERVAL_TRAITS_H

#include <iostream>
#include <string>
#include "elisa_defs.h"

NAMESPACE_ELISA

template <typename I, typename R>
class BasicInterval;

/**
 * @ingroup Interval
 * @class IntervalTraits
 * @brief To be implemented for plugging an interval library
 * in the class Interval
 *
 * <ul>
 * <li> I is the interval type
 * <li> R is the type for bounds
 * </ul>
 */
template <typename I, typename R>
struct IntervalTraits2
{
	/// Type for interval bounds
	typedef R Bound;

	/**
	 * @name Constants
	 */
	//@{
	static const I universe();
	static const I zero();
	static const I one();
	static const I emptySet();
	static const I pi();
	//@}

	/// @brief Copy
	static I& copy(I& lhs, const I& rhs);
	
	/**
	 * @name Arithmetic operations
	 */
	//@{
	static const I 
	plus(const I& lhs, const I& rhs);
	static const I 
	minus(const I& lhs, const I& rhs);
	static const I 
	multiply(const I& lhs, const I& rhs);
	static const I 
	divide(const I& lhs, const I& rhs);

	static const I 
	plus(const I& x);
	static const I 
	minus(const I& x);

	static const I 
	min(const I& lhs, const I& rhs);
	static const I 
	max(const I& lhs, const I& rhs);


	static const I 
	abs(const I& x);

	static const I 
	sqr(const I& x);

	static const I 
	sqrt(const I& x);

	static const I 
	exp(const I& x);

	static const I 
	log(const I& x);

	static const I 
	pow(const I& x, int n);

	static const I 
	root(const I& x, int n);


	static const I 
	sin(const I& x);
	static const I 
	cos(const I& x);
	static const I 
	tan(const I& x);
	static const I 
	sinh(const I& x);
	static const I 
	cosh(const I& x);
	static const I 
	tanh(const I& x);
	static const I 
	asin(const I& x);
	static const I 
	acos(const I& x);
	static const I 
	atan(const I& x);
	static const I 
	asinh(const I& x);
	static const I 
	acosh(const I& x);
	static const I 
	atanh(const I& x);

	static const I 
	asin_rel(const I& lhs, const I& rhs);
	static const I 
	acos_rel(const I& lhs, const I& rhs);
	static const I 
	atan_rel(const I& lhs, const I& rhs);
	static const I 
	asinh_rel(const I& lhs, const I& rhs);
	static const I 
	acosh_rel(const I& lhs, const I& rhs);
	static const I 
	atanh_rel(const I& lhs, const I& rhs);
	static const I 
	sqrt_rel(const I& lhs, const I& rhs);
	static const I 
	root_rel(const I& lhs, const I& rhs);
	static const I 
	invabs_rel(const I& lhs, const I& rhs);
	static const I 
	div_rel(const I& lhs, const I& rhs);
	//@}


	/**
	 * @name Non-arithmetic operations
	 */
	//@{
	/// @name Interval-valued operations on non-interval args
	//@{
	// TODO: hull, sumAll, innerProd
	//@}

	/// @name Numeral-valued unary operations on an interval
	//@{
	/// Inferior bound
	static const Bound
	inf(const I& x);

	/// Superior bound
	static const Bound
	sup(const I& x);

	/// Approximation of the midpoint.
	static const Bound
	mid(const I& x);

	/// Approximation of the integer midpoint.
	static const Bound
	midInt(const I& x);

	/// Return the width of [l,u] = (u-l) upward rounded.
	static const Bound
	width(const I& x);

	/// Magnitude (maximum of absolute values).
	static const Bound
	mag(const I& x);

	/// Mignitude (minimum of absolute values).
	static const Bound
	mig(const I& x);
	//@}

	/// @name Interval-valued unary operations on an interval
	//@{
	/// Return [ceil(l), floor(u)].
	static const I
	toInt(const I& x);

	// TODO: inf, sup, iinf, isup
	//@}

	/// @name Boolean-valued binary operations on an interval
	//@{
	/// If x is a point interval [a,a].
	static bool
	isPoint(const I& x);

	/// If x is equal to the interval [0,0].
	static bool
	isZero(const I& x);

	/// If x contains at most two machine numbers.
	static bool
	isCanonical(const I& x);

	/// If x is an integer interval.
	static bool
	isInt(const I& x);

	/// If x contains at most n machine numbers.
	static bool
	isPreciseCanonical(const I& x, int n);

	/// If x is empty.
	static bool
	isEmpty(const I& x)
	{
		//return (x == Empty);
		return (x == emptySet());
	}
	//@}

	/// @name Boolean-valued binary operations on intervals
	//@{
	static bool
	equalTo(const I& lhs, const I& rhs);
	static bool
	unequalTo(const I& lhs, const I& rhs);
	static bool
	possiblyEqualTo(const I& lhs, const I& rhs);
	static bool
	certainlyEqualTo(const I& lhs, const I& rhs);

	static bool
	lessThan(const I& lhs, const I& rhs);
	static bool
	possiblyLessThan(const I& lhs, const I& rhs);
	static bool
	certainlyLessThan(const I& lhs, const I& rhs);

	// TODO: omega, containedIn
	//@}

	/// @name Numeral-valued binary operations on intervals
	//@{
	// TODO: signed distance, hausdorff distance, projection
	//@}

	/// @name Interval-valued binary operations on intervals
	//@{
	static const I
	intersection(const I& lhs, const I& rhs);

	static const I
	convexHull(const I& lhs, const I& rhs);

	static const I
	innerAddition(const I& lhs, const I& rhs);
	static const I
	innerSubtraction(const I& lhs, const I& rhs);
	//@}

	/// @brief Division with gap
	static const I
	divisionWithGap(const I& lhs, const I& rhs);

	/// @brief Division
	static const std::pair<I, I>
	division(const I& x);

	//@}

	/**
 	 * @name printing methods
 	 */
	//@{
	/// Output of *this on os
	static void print(std::ostream& os, const I& x)
	{
		if (inf(x) == sup(x)) os << inf(x);
		else os << x;
	}

	static void setOutputDigits(int n);
	//@}
};

/**
 * @brief Traits class for interval bounds.
 */
template <typename R>
struct BoundTraits
{
	/// @name Bound operations.
	//@{
	/// Machine number following r.
	static const R
	nextUp(const R& x);

	/// Machine number before r.
	static const R
	nextDown(const R& x);

	/// Conversion from Bound to double.
	static double
	toDouble(const R& x);

	/// Conversion from Bound to integer.
	static int
	toInt(const R& x);
	//@}
};

END_NAMESPACE_ELISA

#endif
